package com.share.device.emqx.handler.impl;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.share.common.rabbit.constant.MqConst;
import com.share.common.rabbit.service.RabbitService;
import com.share.device.domain.Cabinet;
import com.share.device.domain.CabinetSlot;
import com.share.device.domain.PowerBank;
import com.share.device.domain.Station;
import com.share.device.emqx.annotation.GuiguEmqx;
import com.share.device.emqx.constant.EmqxConstants;
import com.share.device.emqx.handler.MassageHandler;
import com.share.device.service.ICabinetService;
import com.share.device.service.ICabinetSlotService;
import com.share.device.service.IPowerBankService;
import com.share.device.service.IStationService;
import com.share.order.api.domain.SubmitOrderVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@GuiguEmqx(topic = EmqxConstants.TOPIC_POWERBANK_UNLOCK)
@RequiredArgsConstructor
public class PowerBankUnlockHandler implements MassageHandler {

    private final ICabinetService cabinetService;

    private final IPowerBankService powerBankService;

    private final ICabinetSlotService cabinetSlotService;

    private final IStationService stationService;

    private final RedisTemplate redisTemplate;

    private final RabbitService rabbitService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void handleMessage(JSONObject message) {
        log.info("收到充电宝解锁消息: {}", message.toJSONString());

        log.info("handleMessage: {}", message.toJSONString());

        // 消息编号
        String messageNo = message.getString("mNo");
        // 防止重复请求
        String key = "powerBank:unlock:" + messageNo;
        log.debug("检查消息重复性，Redis键: {}", key);

        Boolean isExist = redisTemplate.opsForValue().setIfAbsent(key, messageNo, 1, TimeUnit.HOURS);
        if (!isExist) {
            log.info("重复请求，消息编号: {}", messageNo);
            return;
        }
        log.info("消息去重处理成功，消息编号: {}", messageNo);

        // 柜机编号
        String cabinetNo = message.getString("cNo");
        // 充电宝编号
        String powerBankNo = message.getString("pNo");
        // 插槽编号
        String slotNo = message.getString("sNo");
        // 用户id
        Long userId = message.getLong("uId");

        log.debug("解析消息参数 - 柜机编号: {}, 充电宝编号: {}, 插槽编号: {}, 用户ID: {}", cabinetNo, powerBankNo, slotNo, userId);

        if (StringUtils.isEmpty(cabinetNo) || StringUtils.isEmpty(powerBankNo) || StringUtils.isEmpty(slotNo) || null == userId) {
            log.error("消息参数不完整: {}", message.toJSONString());
            return;
        }

        log.info("消息参数校验通过 - 柜机编号: {}, 充电宝编号: {}, 插槽编号: {}, 用户ID: {}", cabinetNo, powerBankNo, slotNo, userId);

        // 获取柜机
        log.debug("开始查询柜机信息，柜机编号: {}", cabinetNo);
        Cabinet cabinet = cabinetService.getBtCabinetNo(cabinetNo);
        if (cabinet == null) {
            log.error("未找到对应柜机，柜机编号: {}", cabinetNo);
            return;
        }
        log.info("获取柜机信息成功，柜机ID: {}, 柜机编号: {}", cabinet.getId(), cabinetNo);

        // 获取充电宝
        log.debug("开始查询充电宝信息，充电宝编号: {}", powerBankNo);
        PowerBank powerBank = powerBankService.getByPowerBankNo(powerBankNo);
        if (powerBank == null) {
            log.error("未找到对应充电宝，充电宝编号: {}", powerBankNo);
            return;
        }
        log.info("获取充电宝信息成功，充电宝ID: {}, 充电宝编号: {}", powerBank.getId(), powerBankNo);

        // 获取插槽
        log.debug("开始查询插槽信息，柜机ID: {}, 插槽编号: {}", cabinet.getId(), slotNo);
        CabinetSlot cabinetSlot = cabinetSlotService.getBtSlotNo(cabinet.getId(), slotNo);
        if (cabinetSlot == null) {
            log.error("未找到对应插槽，柜机ID: {}, 插槽编号: {}", cabinet.getId(), slotNo);
            return;
        }
        log.info("获取插槽信息成功，插槽ID: {}, 插槽编号: {}", cabinetSlot.getId(), slotNo);

        // 获取站点
        log.debug("开始查询站点信息，柜机ID: {}", cabinet.getId());
        Station station = stationService.getByCabinetId(cabinet.getId());
        if (station == null) {
            log.error("未找到对应站点，柜机ID: {}", cabinet.getId());
            return;
        }
        log.info("获取站点信息成功，站点ID: {}, 站点名称: {}", station.getId(), station.getName());

        // 更新充电宝状态
        // 状态（0:未投放 1：可用 2：已租用 3：充电中 4：故障）
        log.info("更新充电宝状态，充电宝ID: {}, 原状态: {}, 新状态: {}", powerBank.getId(), powerBank.getStatus(), "2");
        powerBank.setStatus("2");
        powerBankService.updateById(powerBank);
        log.info("充电宝状态更新成功，充电宝ID: {}", powerBank.getId());

        // 更新插槽状态
        // 状态（1：占用 0：空闲）
        log.info("更新插槽状态，插槽ID: {}, 原状态: {}, 新状态: {}", cabinetSlot.getId(), cabinetSlot.getStatus(), "0");
        cabinetSlot.setStatus("0");
        cabinetSlot.setPowerBankId(null);
        cabinetSlot.setUpdateTime(new Date());
        cabinetSlotService.updateById(cabinetSlot);
        log.info("插槽状态更新成功，插槽ID: {}", cabinetSlot.getId());

        // 更新柜机信息
        log.info("开始更新柜机统计信息，柜机ID: {}", cabinet.getId());
        int freeSlots = cabinet.getFreeSlots() + 1;
        cabinet.setFreeSlots(freeSlots);
        int usedSlots = cabinet.getUsedSlots() - 1;
        cabinet.setUsedSlots(usedSlots);
        // 可以借用
        int availableNum = cabinet.getAvailableNum() - 1;
        cabinet.setAvailableNum(availableNum);
        cabinet.setUpdateTime(new Date());
        cabinetService.updateById(cabinet);

        log.info("柜机统计信息更新成功，柜机ID: {} - 空闲插槽: {}, 已用插槽: {}, 可用充电宝: {}", cabinet.getId(), freeSlots, usedSlots, availableNum);

        // 构建订单对象
        SubmitOrderVo submitOrderVo = new SubmitOrderVo();
        submitOrderVo.setMessageNo(messageNo);
        submitOrderVo.setUserId(userId);
        submitOrderVo.setPowerBankNo(powerBankNo);
        submitOrderVo.setStartStationId(station.getId());
        submitOrderVo.setStartStationName(station.getName());
        submitOrderVo.setStartCabinetNo(cabinetNo);
        submitOrderVo.setFeeRuleId(station.getFeeRuleId());
        log.info("构建订单对象: {}", JSONObject.toJSONString(submitOrderVo));
        // 发送信息
        rabbitService.sendMessage(MqConst.EXCHANGE_ORDER, MqConst.ROUTING_SUBMIT_ORDER, JSONObject.toJSONString(submitOrderVo));

        log.info("充电宝解锁处理完成，待构建订单 - 用户ID: {}, 充电宝ID: {}, 柜机ID: {}", userId, powerBank.getId(), cabinet.getId());

    }
}
